package com.jumi.microservice.order.handler;

import com.alibaba.fastjson.JSON;
import com.jumi.microservice.common.base.dto.ResponseResult;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.common.redis.RedisCache;
import com.jumi.microservice.domain.OrderInventoryDTO;
import com.jumi.microservice.domain.OrderInventoryItemDTO;
import com.jumi.microservice.domain.OrderItemDTO;
import com.jumi.microservice.domain.SkuDTO;
import com.jumi.microservice.dto.reponse.ActivityLimitDTO;
import com.jumi.microservice.dto.reponse.AddressResponse;
import com.jumi.microservice.dto.reponse.GoodOrderBuyDTO;
import com.jumi.microservice.dto.reponse.UserExternalResponse;
import com.jumi.microservice.enumerate.OrderStatusEnum;
import com.jumi.microservice.enums.Level;
import com.jumi.microservice.order.context.GoodsSkuContext;
import com.jumi.microservice.order.context.OrderCreateContext;
import com.jumi.microservice.order.context.TransHandlerContext;
import com.jumi.microservice.service.*;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Dirk
 * @Date 2020-08-05 13:56
 */
@Component
public class BuyProductInitHandler implements TransHandler {

    private static final Logger log = LoggerFactory.getLogger(TransHandler.class);

    @Override
    public boolean isAsync() {
        return false;
    }

    @DubboReference
    private IOrderInventoryService orderInventoryService;

    @DubboReference
    private IUserExternalService userExternalService;

    @DubboReference
    private IOrderDubboService orderDubboService;

    @DubboReference
    private IAddressService addressService;

    @DubboReference
    private GorderActivityApi gorderActivityApi;

    @DubboReference
    private BasicDataService basicDataService;

    @Resource
    RedisCache redisCache;
    @Resource
    RedisTemplate redisTemplate;


    private static final String user_info = "user_info:";

    @Override
    public boolean handler(TransHandlerContext context) {
        OrderCreateContext ctx = (OrderCreateContext) context;
        ctx.setOrderStatus(OrderStatusEnum.READY_TO_PAY);

        // 活动校验
        Map<Long, Integer> skuMap = ctx.getGoodsList().stream()
                .collect(Collectors.toMap(goodsSkuContext -> Long.valueOf(goodsSkuContext.getGoodsId()),
                        GoodsSkuContext::getGoodsAmount));
//        List<SkuDTO> skuList = basicDataService.getGoodsSkuListByIds(new ArrayList<>(skuMap.keySet()));
        // 尝试从redis获取商品详情
        List<Long> skuIds = new ArrayList<>(skuMap.keySet());
        List<String> skuIdsKey = skuIds.stream().map(skuId -> "JUMI:SKU:".concat(skuId.toString())).collect(Collectors.toList());
        List<Object> skuList = redisTemplate.opsForValue().multiGet(skuIdsKey);
        List<SkuDTO> skuDTOList = new ArrayList<>();
        if (!ObjectUtils.isEmpty(skuList)) {
            skuDTOList = skuList.stream().filter(Objects::nonNull).map(o -> (SkuDTO) o).collect(Collectors.toList());
        }
        log.info("redis获取的spu信息 [{}]", JSON.toJSONString(skuDTOList));
        // 将redis没有的sku通过服务调用获取
        List<Long> subSkuIds = skuDTOList.stream().map(SkuDTO::getId).collect(Collectors.toList());
        skuIds.removeAll(subSkuIds);
        if (skuIds.size() > 0) {
            Map<Long, Long> skuSpuMap = basicDataService.getSpuIdBySkuIds(skuIds);
            log.info("接口获取的sku-spu对应关系 [{}]", skuSpuMap);
            skuDTOList.addAll(skuSpuMap.entrySet().stream().map(k -> {
                SkuDTO skuDTO = new SkuDTO();
                skuDTO.setGoodsId(k.getValue());
                skuDTO.setId(k.getKey());
                return skuDTO;
            }).collect(Collectors.toList()));
        }
        Map<Long, Integer> spuMap = skuDTOList.stream().map(SkuDTO::getGoodsId)
                .collect(Collectors.toSet()).stream()
                .collect(Collectors.toMap(spu -> spu, amount -> 0));
        skuDTOList.forEach(skuDTO -> {
            Long sku = skuDTO.getId();
            Long spu = skuDTO.getGoodsId();
            spuMap.put(spu, spuMap.get(spu) + skuMap.get(sku));
        });
        List<GoodOrderBuyDTO> spuOrders = new ArrayList<>();

        spuMap.keySet().forEach(spu -> {
            GoodOrderBuyDTO goodOrderBuyDTO = new GoodOrderBuyDTO();
            goodOrderBuyDTO.setSpuId(spu);
            goodOrderBuyDTO.setOrderNum(spuMap.get(spu));
            spuOrders.add(goodOrderBuyDTO);
        });
        log.info("活动校验参数: [{}], [{}]", JSON.toJSONString(spuOrders), ctx.getUid());
        List<ActivityLimitDTO> activityLimitDTOs;
        activityLimitDTOs = gorderActivityApi.goodsLimitBySpuid(spuOrders, ctx.getUid());
        log.info("活动校验返回: [{}]", JSON.toJSONString(activityLimitDTOs));

        // redis获取用户角色
        String key = user_info.concat(ctx.getUid().toString());
        Map<String, Object> userInfoCacheMap = redisCache.getCacheMap(key);
        log.info("redis获取的用户信息: [{}]", JSON.toJSONString(userInfoCacheMap));
        Byte userRole = 0;
        if (userInfoCacheMap != null && userInfoCacheMap.size() > 0) {
            if (userInfoCacheMap.get("level") != null && !userInfoCacheMap.get("level").toString().isEmpty()) {
                userRole = JSON.parseObject(userInfoCacheMap.get("level").toString()).getByte("value");
            }
        } else {
            UserExternalResponse user = userExternalService.getUserByUid(ctx.getUid().intValue());
            log.info("接口获取的用户信息: [{}]", JSON.toJSONString(user));
            userRole = user.getLevel();
        }
        ctx.setUserRole(userRole);
        // 收件人信息
        AddressResponse addressResponse = addressService.getAddressById(ctx.getReceiverId());
        if (addressResponse == null) {
            throw new BaseException(500, "收件人地址错误");
        }
        log.info("收件人信息: [{}]", JSON.toJSONString(addressResponse));
        ctx.setReceiverName(addressResponse.getTrueName());
        ctx.setReceiverPhone(addressResponse.getMobPhone());
        ctx.setReceiverAddress(addressResponse.getAreaInfo().concat(" ").concat(addressResponse.getAddress()));
        // 省级地区id，运费模板使用省级id进行匹配
        Long areaId = addressResponse.getProvinceId().longValue();

        // 扣库存并获取商品详情
        List<OrderItemDTO> orderItemDTOList = new ArrayList<>();
        Date requestDate = new Date();
        ctx.getGoodsList().forEach(goodsSkuContext -> {
            OrderItemDTO orderItemDTO = new OrderItemDTO();
            orderItemDTO.setGoodsSkuId(goodsSkuContext.getGoodsId().longValue());
            orderItemDTO.setPurchaseQuantity(goodsSkuContext.getGoodsAmount());
            orderItemDTO.setUserAccountId(ctx.getUid());
            orderItemDTO.setAreaId(areaId);
            orderItemDTO.setRequestTime(requestDate);
            orderItemDTOList.add(orderItemDTO);
        });
        List<OrderInventoryItemDTO> orderInventoryItemList;
        try {
            log.info("获取商品详情参数: [{}]", JSON.toJSONString(orderItemDTOList));
            ResponseResult<OrderInventoryDTO> responseResult = orderInventoryService.informSubmitOrderEvent(orderItemDTOList);
            log.info("商品详情返回值; [{}]", JSON.toJSONString(responseResult));
            orderInventoryItemList = responseResult.getData().getOrderInventoryItems();
            if (responseResult.getData().getIsEnough().equals(0)) {
                // 库存不足
                OrderInventoryItemDTO orderInventoryItem = orderInventoryItemList.stream()
                        .filter(orderInventoryItemDTO -> orderInventoryItemDTO.getIsEnough().equals(0))
                        .findFirst().orElse(new OrderInventoryItemDTO());
                throw new BaseException(600, orderInventoryItem.getGoodsSkuName() + responseResult.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(500, e.getMessage() == null ? "扣库存失败" : e.getMessage());
        }

        Byte finalUserRole = userRole;
        List<ActivityLimitDTO> finalActivityLimitDTOs = new ArrayList<>(activityLimitDTOs);
        // 商品详情转上下文参数
        List<GoodsSkuContext> goodsSkuContextList = ctx.getGoodsList();
        goodsSkuContextList.forEach(goodsSkuContext -> {
            OrderInventoryItemDTO orderInventoryItem = orderInventoryItemList.stream()
                    .filter(orderInventoryItemDTO ->
                            orderInventoryItemDTO.getSkuId().equals(goodsSkuContext.getGoodsId().longValue()))
                    .findFirst().orElse(new OrderInventoryItemDTO());
            goodsSkuContext.setGoodsName(orderInventoryItem.getGoodsSkuName());
            goodsSkuContext.setGoodsSpec(orderInventoryItem.getSpecName());
            goodsSkuContext.setSpuId(orderInventoryItem.getGoodsId().intValue());
            goodsSkuContext.setIsGroup(orderInventoryItem.getIsCompose().byteValue());
            ActivityLimitDTO activityLimitDTO = finalActivityLimitDTOs.stream()
                    .filter(a -> a.getSpuId().equals(goodsSkuContext.getSpuId().longValue())).findFirst().orElse(null);
            if (activityLimitDTO != null) {
                goodsSkuContext.setActivityId(activityLimitDTO.getActivityId());
                goodsSkuContext.setActivityType(activityLimitDTO.getActivityType());
            }
            Byte verifyStatus = new Byte("0");
            if (orderInventoryItem.getShouldWarehouseId() != null && orderInventoryItem.getActualWarehouseId() != null) {
                if (!orderInventoryItem.getShouldWarehouseId().equals(orderInventoryItem.getActualWarehouseId())) {
                    verifyStatus = new Byte("1");
                }
                goodsSkuContext.setShouldWarehouse(orderInventoryItem.getShouldWarehouseId().intValue());
                goodsSkuContext.setRealWarehouse(orderInventoryItem.getActualWarehouseId().intValue());
            }
            goodsSkuContext.setVerifyStatus(verifyStatus);
            // 团购价
            BigDecimal promotionPrice = orderInventoryItem.getGoodsPrice();
            // 店长价
            BigDecimal platinumPrice = orderInventoryItem.getPlatinumPrice();
            // 优秀店长价
            BigDecimal diamondsPrice = orderInventoryItem.getDiamondsPrice();
            // 金牌推广商价
            BigDecimal kingPrice = orderInventoryItem.getKingPrice();
            goodsSkuContext.setGoodsPromotionPrice(promotionPrice);
            goodsSkuContext.setGoodsPlatinumPrice(platinumPrice);
            goodsSkuContext.setGoodsDiamondsPrice(diamondsPrice);
            goodsSkuContext.setGoodsKingPrice(kingPrice);
            goodsSkuContext.setGainPrice(orderInventoryItem.getGetOrderPrice());
            goodsSkuContext.setGoodsCostPrice(orderInventoryItem.getGoodsCostprice());
            // 根据角色获取价格
            goodsSkuContext.setGoodsPrice(getPriceByRole(finalUserRole, promotionPrice, platinumPrice, diamondsPrice, kingPrice));
            // 运费
            goodsSkuContext.setGoodsFreightFee(orderDubboService.getGoodsFreightFee(orderInventoryItem.getFreightTempDTO(), areaId.toString(),
                    orderInventoryItem.getGoodsGrossWeight().multiply(new BigDecimal(goodsSkuContext.getGoodsAmount())),
                    goodsSkuContext.getGoodsAmount()));
            goodsSkuContext.setGoodsCoverImg(orderInventoryItem.getGoodsPropertyImage());
            goodsSkuContext.setGoodsWeight(orderInventoryItem.getGoodsGrossWeight());
            if (orderInventoryItem.getCateId() != null) {
                goodsSkuContext.setGoodsLabel(orderInventoryItem.getCateId().intValue());
            }
            goodsSkuContext.setSelfFlag(orderInventoryItem.getIsShelf().byteValue());
            goodsSkuContext.setSupplierId(orderInventoryItem.getSupplyId().intValue());
            goodsSkuContext.setIsPre(orderInventoryItem.getIsPre());
            if (orderInventoryItem.getLockedStockId() == null) {
                throw new BaseException(500, "扣库存失败");
            }
            goodsSkuContext.setWarehouseSn(orderInventoryItem.getLockedStockId().toString());
            goodsSkuContext.setDrainage(orderInventoryItem.getDrainage().byteValue());
            goodsSkuContext.setFixRebate(orderInventoryItem.getFixRebate().byteValue());
            Integer isImport = orderInventoryItem.getIsImport();
            goodsSkuContext.setIsImport(isImport.byteValue());
        });
        ctx.setOrderPromotionAmount(goodsSkuContextList.stream()
                .map(goodsSkuContext -> goodsSkuContext.getGoodsPromotionPrice()
                        .multiply(new BigDecimal(goodsSkuContext.getGoodsAmount())))
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        ctx.setOrderAmount(goodsSkuContextList.stream()
                .map(goodsSkuContext -> goodsSkuContext.getGoodsPrice()
                        .multiply(new BigDecimal(goodsSkuContext.getGoodsAmount())))
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        ctx.setFreightFee(goodsSkuContextList.stream()
                .map(GoodsSkuContext::getGoodsFreightFee)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        ctx.setPayAmount(ctx.getOrderAmount().add(ctx.getFreightFee()));

        return true;
    }

    /**
     * 根据角色获取用户价格
     *
     * @param userRole       用户角色
     * @param promotionPrice 团购价
     * @param platinumPrice  店长价
     * @param diamondsPrice  优秀店长价
     * @param kingPrice      金牌推广商价
     * @return 会员价
     */
    public BigDecimal getPriceByRole(Byte userRole, BigDecimal promotionPrice, BigDecimal platinumPrice,
                                     BigDecimal diamondsPrice, BigDecimal kingPrice) {
        Level role = Level.getLevelByValue(userRole.intValue());
        if (Level.user.equals(role)) {
            return promotionPrice;
        } else if (Level.manager.equals(role)) {
            return platinumPrice;
        } else if (Level.goodManager.equals(role)) {
            return diamondsPrice;
        } else if (Level.gold.equals(role)) {
            return kingPrice;
        } else {
            return promotionPrice;
        }
    }
}
